Slient Blog

Java装箱与拆箱

2017-05-04

Java拆箱和装箱

使用包装器类和装箱

包装器类的主要用途

为基本类型提供分类功能,这些功能中的大多数与各种转换相关:如在基本类型之间与String对象进行转换。

创建包装器对象

除了Character之外,所有的包装器都提供两个构造函数
一个是基本类型,另一个就是字符串,如:

1
2
3
4
Integer i1 = new Integer(10);
Integer i2 = new Integer("10");
Character类只提供一种构造函数
Character c1 = new Character('a');

Boolean包装器的构造函数可以是带有bollean值true或false,或者一个不区分大小写”true”或是“false”但是需要注意的一点是如下代码:

1
2
3
4
Bollean flag = new Bollean("true");
if(flag)
{
}

编译器自动把Boolean“取消装箱” 成一个boolean.

valueOf()方法

它是由包装类的静态方法

它还有一个可以带额外参数(int radix)的重载方法,返回一个包装器类

1
Integer i2= Integer.valueOf("101011",2);

第二个参数表示进制, 首先将101011转换成43 然后将43赋值给id对象

xxxValue()方法

用于把包装的值转换为一个基本类型的数据

1
2
3
Integer i2 = new Integer(55);
byte b = i2.byteValue();
double d = i2.doubleValue();

pareseXXX()方法

parseXXX()与valueOf()都是以String作参数,如果String形式不对,则抛出NumberFormatException
它也是包装器的一个静态方法,但其返回的是一个基本类型的数据。

1
2
double d = Double.parseDouble("1.23"):
parseXXX()也可以像valueOf()一样传一个基数参数

自动装箱

1
2
3
4
5
6
7
8
9
Integer y = new Integer(567); // 创建对象
y++; //自动拆箱,自增,再自动装箱(因为y是一个包装器类)
System.out.println("y = " + y);
Integer y = new Integer(567); // 创建对象
int x = y.intValue(); // 拆箱操作
x++; // 折箱后自增
y = new Integer(x); // 重新装箱成对象
System.out.println("y = " + i);
1
2
3
4
5
6
7
8
9
10
Integer y = 567;
Integer x = y;
System.out.println(y==x);
y++;
System.out.println(x + " " + y);
System.out.println(y==x);
输出结果
true
567 568
false

y++相当于以下操作

1
2
3
int x2= y.intValue();
x2++;
y = new Integer(x2);

1
2
3
4
5
6
7
8
9
10
11
12
13
Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4)
{
System.out.println("same object");
}
if(i3.equals(i4))
{
System.out.println("meaningfully equal");
}
输出结果:
same object
meaningfully equal
1
2
3
4
5
6
7
8
9
10
11
12
13
Integer i1 = 500;
Integer i2 = 500;
if(il != i2)
{
System.out.println("different objects");
}
if(i1.equals(i2))
{
System.out.println("meaningfully equal");
}
输出结果:
different objects
meaningfully equal

为什么i3和i4是相同的对象,然而i1和i2是不同的对象呢

1
In order to save memory, two instances of the following wrapper objects will always be = = when their primitive values are the same:

-128–127之间的值,它们被装箱为Integer对象后,会在内存中被重用,超过这个值的时候每次装箱是会产生新的对象

box&unbox给重载带来的问题

1
2
3
4
5
6
7
8
class Test{
static void go(Integer x) { System.out.println("Integer"); }
static void go(long x) { System.out.println("long"); }
public static void main(String [] args) {
int i = 5;
go(i);
}
}

编译器选择的是加宽操作而不是装箱

1
2
3
4
5
6
7
8
class Test{
static void go(int x, int y) { System.out.println("int,int");}
static void go(byte... x) { System.out.println("byte ... "); }
public static void main(String[] args) {
byte b = 5;
go(b,b);
}
}

加宽会优先于var-arg执行


加宽优于装箱
加宽优于var-arg
那装箱与var-arg的关系如何???

1
2
3
4
5
6
7
8
9
class Test{
static void go(Byte x, Byte y)
{ System.out.println("Byte, Byte"); }
static void go(byte... x) { System.out.println("byte... "); }
public static void main(String [] args) {
byte b = 5;
go(b,b); // which go() will be invoked?
}
}

装箱会优于var-arg操作

加宽>装箱>var-arg

Attention

1
2
3
4
5
6
7
class Test{
public static void main(String [] args) {
Test d = new Test();
d.test(new Integer(5));
}
void test(Long x) { }
}

编译错误

加宽对于对象来说是依赖于继承的

从一个包装器类加宽到另一个包装器类是非法的,因为包装器之间的平等的,不符合IS-a原则

Short IS-A Integer 这种说法是错误的

总结

  • 基本加宽使用可能“最小的”方法参数
  • 不能先加宽,后装箱(int 不能转成Long)
  • 可以先装箱,后加宽(int可以通过Integer变成object,Integer继承object)
Tags: Java
使用微信添加

若你觉得我的文章对你有帮助,请添加我为好友

扫描二维码,分享此文章